
#include <cameraviewer.h>
#include <QOpenGLWidget>
#include <QPainter>
#include <boost/interprocess/exceptions.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <src/common/base/slog.hpp>
#include <data_struct.h>
#include <QtCore>
#include <QGLWidget>
#include <cameraviewer.h>


QImage Mat2QImage(cv::Mat cvImg) {
    QImage qImg;
    if (cvImg.channels() == 3) {

        cv::cvtColor(cvImg, cvImg, cv::COLOR_BGR2RGB);
        qImg = QImage((const unsigned char *) (cvImg.data),
                      cvImg.cols, cvImg.rows,
                      cvImg.cols * cvImg.channels(),
                      QImage::Format_RGB888);
    } else if (cvImg.channels() == 1) {
        qImg = QImage((const unsigned char *) (cvImg.data),
                      cvImg.cols, cvImg.rows,
                      cvImg.cols * cvImg.channels(),
                      QImage::Format_Indexed8);
    } else {
        qImg = QImage((const unsigned char *) (cvImg.data),
                      cvImg.cols, cvImg.rows,
                      cvImg.cols * cvImg.channels(),
                      QImage::Format_RGB888);
    }

    return qImg;

}

CameraViewer::CameraViewer(QWidget *parent)
        : QOpenGLWidget(parent) {
    mSceneChanged = false;
    mBgColor = QColor::fromRgb(150, 150, 150);

    mOutH = 0;
    mOutW = 0;
    mImgratio = 4.0f / 3.0f; // Default image ratio

    mPosX = 0;
    mPosY = 0;

}

CameraViewer::~CameraViewer() {
}

void CameraViewer::paintGL() {
    makeCurrent();

    if (!mSceneChanged)
        return;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    renderImage();

    mSceneChanged = false;
}

void CameraViewer::initializeGL() {
}

void CameraViewer::updateScene() {
    if (mSceneChanged && this->isVisible())
        QOpenGLWidget::update();
}

void CameraViewer::renderImage() {
    makeCurrent();

    glClear(GL_COLOR_BUFFER_BIT);

    if (!mRenderQtImg.isNull()) {
        glLoadIdentity();

        QImage image; // the image rendered

        glPushMatrix();
        {
            int imW = mRenderQtImg.width();
            int imH = mRenderQtImg.height();

            // The image is to be resized to fit the widget?
            if (imW != this->size().width() &&
                imH != this->size().height()) {

                image = mRenderQtImg.scaled( //this->size(),
                        QSize(mOutW, mOutH),
                        Qt::IgnoreAspectRatio,
                        Qt::SmoothTransformation
                );

                //qDebug( QString( "Image size: (%1x%2)").arg(imW).arg(imH).toAscii() );
            } else
                image = mRenderQtImg;

            // --->Centering image in draw area

            glRasterPos2i(mPosX, mPosY);
            // < --- Centering image in draw area

            imW = image.width();
            imH = image.height();

            glDrawPixels(imW, imH, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
        }
        glPopMatrix();

        // end
        glFlush();
    }
}

bool CameraViewer::showImage(cv::Mat image) {
    image.copyTo(mOrigImage);

    mImgratio = (float) image.cols / (float) image.rows;

    if (mOrigImage.channels() == 3)
        mRenderQtImg = QImage((const unsigned char *) (mOrigImage.data),
                              mOrigImage.cols, mOrigImage.rows,
                              mOrigImage.step, QImage::Format_RGB888).rgbSwapped();
    else if (mOrigImage.channels() == 1)
        mRenderQtImg = QImage((const unsigned char *) (mOrigImage.data),
                              mOrigImage.cols, mOrigImage.rows,
                              mOrigImage.step, QImage::Format_Indexed8);
    else
        return false;

    mRenderQtImg = QGLWidget::convertToGLFormat(mRenderQtImg);

    mSceneChanged = true;

    updateScene();

    return true;
}

void CameraViewer::update_image() {
    if (is_setMsq) {
        glClear(GL_ACCUM_BUFFER_BIT);
        try {
            unsigned int priority = 0;
            boost::interprocess::message_queue::size_type recvd_size = 0;

            boost::posix_time::ptime timeout =
                    boost::posix_time::microsec_clock::universal_time() + boost::posix_time::microseconds(1);
            if (mobilesearch_video_message_queue->get_num_msg() > 0) {
                char *package_frame_buffer = new char[PACKAGE_SIZE];
                char *frame_buffer;
                memset(package_frame_buffer, 0, PACKAGE_SIZE);

                mobilesearch_video_message_queue->receive(
                        package_frame_buffer, PACKAGE_SIZE, recvd_size, priority);
                data_package_t dataPackage;

                memcpy(&dataPackage, package_frame_buffer, sizeof(data_package_t));
                frame_buffer = dataPackage.data;

                int width = 640;
                int heigh = 480;
                int chanels = 3;
                int data_length = width * heigh * chanels;
                cv::Mat recive_img(cv::Size(640, 480), CV_8UC3);
                for (int i = 0; i < data_length; i++) {
                    recive_img.at<cv::Vec3b>(i / (width * chanels), (i % (width * chanels)) / chanels)[i %
                                                                                                       chanels] = frame_buffer[i];
                }
                showImage(recive_img);
                free(package_frame_buffer);

            }
        } catch (boost::interprocess::interprocess_exception &e) {
            slog::warn << "Recive MobileSearchVideoMessageQueue Error" << slog::endl;
        }
    } else {
        slog::err << "没有配置目标消息队列" << slog::endl;
    }
}

void CameraViewer::resizeGL(int width, int height) {
    makeCurrent();
    glViewport(0, 0, (GLint) width, (GLint) height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(0, width, 0, height, 0, 1); // To Draw image in the center of the area

    glMatrixMode(GL_MODELVIEW);

    // ---> Scaled Image Sizes
    mOutH = width / mImgratio;
    mOutW = width;

    if (mOutH > height) {
        mOutW = height * mImgratio;
        mOutH = height;
    }

    emit imageSizeChanged(mOutW, mOutH);
    // < --- Scaled Image Sizes

    mPosX = (width - mOutW) / 2;
    mPosY = (height - mOutH) / 2;

    mSceneChanged = true;

    updateScene();
}

bool CameraViewer::set_target_msq(std::string &msq_name) {
    if (!is_setMsq) {
        try {
            mobilesearch_video_message_queue = boost::shared_ptr<boost::interprocess::message_queue>(
                    new boost::interprocess::message_queue(
                            boost::interprocess::open_only,
                            msq_name.c_str()
                    ));
            is_setMsq = true;
            slog::success << "Message Queue: Open " << msq_name << " Success" << slog::endl;
        } catch (boost::interprocess::interprocess_exception &e) {
            slog::err << "Message Queue: Open " << msq_name << " Error" << e.what() << slog::endl;
        }
    } else {
        slog::err << "Message Queue: " << msq_name << msq_name << " Had been Opened" << slog::endl;
    }
}





